#include "CRecord.h"
#include "irecordower.h"

#define INVALID_OP_INDEX	-1
#define MAX_OP_RECORD_STEP	20

CRecord::CRecord(void* ppRogram)
{
	m_pPrgram			= ppRogram;
	m_pcallback			= NULL;
	m_nOPSUMIndex		= INVALID_OP_INDEX;
	m_nOPCurrentIndex	= INVALID_OP_INDEX;
	m_bCanRecord		= false;
}


CRecord::~CRecord()
{
}

void CRecord::Clear()
{
	EnterSection();

	m_mapOperateBakRecords.clear();
	m_mapOperateNexRecords.clear();

	LeaveSection();
}

void CRecord::StartNewSerial()
{
	EnterSection();
	if (!m_bCanRecord)
	{
		LeaveSection();
		return;
	}

	++m_nOPSUMIndex;
	m_nOPCurrentIndex = m_nOPSUMIndex;

	LeaveSection();
}

void CRecord::SetChangeCallback(PCHANGECALLBACK pcallback)
{
	m_pcallback = pcallback;
}
void CRecord::GetBackRecords(list<SRecordInfo>& vecBackList)
{
	map<int, CRecordInfo>::iterator it = m_mapOperateBakRecords.begin();
	for (; it != m_mapOperateBakRecords.end(); ++it)
	{
		SRecordInfo sS =
			Trans2SAOILogicRecord(it->second);

		vecBackList.push_back(sS);
	}
}
void CRecord::GetCurrentRecords(SRecordInfo& currentRecord)
{
	currentRecord =
		Trans2SAOILogicRecord(m_currentRecord);
}
void CRecord::GetNextRecords(list<SRecordInfo>& nextList)
{
	map<int, CRecordInfo>::iterator it = m_mapOperateNexRecords.begin();
	for (; it != m_mapOperateNexRecords.end(); ++it)
	{
		SRecordInfo sS =
			Trans2SAOILogicRecord(it->second);

		nextList.push_back(sS);
	}
}
void CRecord::GetRecords(list<SRecordInfo>& vecBackList, SRecordInfo& currentRecord, list<SRecordInfo>& nextList)
{
	EnterSection();

	GetBackRecords(vecBackList);
	GetCurrentRecords(currentRecord);
	GetNextRecords(nextList);

	LeaveSection();
}

void CRecord::UnableRecord()
{
	EnterSection();

	m_bCanRecord = false;

	LeaveSection();
}
void CRecord::EnableRecord()
{
	EnterSection();

	m_bCanRecord = true;

	LeaveSection();
}

void CRecord::RecordData(ERECORD_DATA_OPERATE_TYPE otype, ERECORD_DATATYPE dType, 
    CLComString opdesc, CLComString id)
{
	if (!m_bCanRecord)
	{
		return;
	}
	EnterSection();

	CRecordItem item;
	item.SetOpType(otype);
	item.SetDataType(dType);
	item.SetOPID(id);

	map<int, CRecordInfo>::iterator it 
		= m_mapOperateBakRecords.find(m_nOPCurrentIndex);
	if (it != m_mapOperateBakRecords.end())
	{
        if (((IRecordOwer*)m_pPrgram)->RecordOperate(
			ERECORD_OPERATE_TYPE_BACKUP,
			item))
		{
			it->second.AddRecordItem(item);
		}
	}
	else
	{
        if (((IRecordOwer*)m_pPrgram)->RecordOperate(
			ERECORD_OPERATE_TYPE_BACKUP,
			item))
		{
			if (m_mapOperateBakRecords.size() >= MAX_OP_RECORD_STEP)
			{
				m_mapOperateBakRecords.erase(m_mapOperateBakRecords.begin());
			}
			CRecordInfo recordinfo;
			recordinfo.SetOpIndex(m_nOPCurrentIndex);
			recordinfo.SetOpDesc(opdesc);

			recordinfo.AddRecordItem(item);

			m_mapOperateBakRecords[m_nOPCurrentIndex] = recordinfo;
		}
	}

	LeaveSection();
}

bool CRecord::GoBack(int recordID)
{
	EnterSection();

	if (recordID == m_nOPCurrentIndex)
	{
		LeaveSection();
		return false;
	}

	for (int i = (m_currentRecord.GetOpIndex() - 1); i >= recordID; --i)
	{
		map<int, CRecordInfo>::iterator it = m_mapOperateBakRecords.find(i);
		if (it != m_mapOperateBakRecords.end())
		{
			int nIndex = 0;
			CRecordItem item;
			while (it->second.GetItem(item, nIndex++))
			{
                ((IRecordOwer*)m_pPrgram)->RecordOperate(
					ERECORD_OPERATE_TYPE_GOBACK,
					item);
			}
			m_mapOperateNexRecords[m_currentRecord.GetOpIndex()] 
				= m_currentRecord;

			m_currentRecord = it->second;

			m_mapOperateBakRecords.erase(it->first);
		}
	}

	LeaveSection();

	return true;
}
bool CRecord::GoNext(int recordID)
{
	EnterSection();

	if (recordID == m_nOPCurrentIndex)
	{
		LeaveSection();
		return false;
	}

	for (int i = (m_currentRecord.GetOpIndex() + 1); i <= recordID; ++i)
	{
		map<int, CRecordInfo>::iterator it = m_mapOperateNexRecords.find(i);
		if (it != m_mapOperateNexRecords.end())
		{
			int nIndex = 0;
			CRecordItem item;
			while (it->second.GetItem(item, nIndex++))
			{
                ((IRecordOwer*)m_pPrgram)->RecordOperate(
					ERECORD_OPERATE_TYPE_GONEXT,
					item);
			}
			
			m_mapOperateBakRecords[m_currentRecord.GetOpIndex()] = m_currentRecord;

			m_currentRecord = it->second;

			m_mapOperateNexRecords.erase(it->first);
		}
	}

	LeaveSection();

	return true;
}

bool CRecord::HaveNext()
{
	return m_mapOperateNexRecords.size() > 0;
}
bool CRecord::HaveBack()
{
	return m_mapOperateBakRecords.size() > 0;
}
bool CRecord::HaveChange()
{
	return HaveNext() || HaveBack();
}
void CRecord::Trans2SAOILogicRecord(CRecordInfo& sourceRecord, SRecordInfo& dstRecord)
{
	dstRecord._nOPIndex		= sourceRecord.GetOpIndex();
	CRecordItem item;
	int nItemIndex = 0;
	if (sourceRecord.GetItem(item, nItemIndex))
	{
		do 
		{
			dstRecord._eOPType = item.GetOpType();
			dstRecord._eDataType = item.GetDataType();
			if (dstRecord._opIDS != "")
			{
				dstRecord._opIDS += ";";
			}
			dstRecord._opIDS += item.GetOPID().GetChars();
		} while (sourceRecord.GetItem(item, ++nItemIndex));
	}

	dstRecord._opDesc		= sourceRecord.GetOpDesc().GetChars();
}
SRecordInfo CRecord::Trans2SAOILogicRecord(CRecordInfo& sourceRecord)
{
	SRecordInfo dstRecord;
	Trans2SAOILogicRecord(sourceRecord, dstRecord);

	return dstRecord;
}
